package com.yufubao.service.service.applet.elasticsearch.impl;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.yufubao.framework.builder.es.RequestOptionsBuilder;
import com.yufubao.framework.constant.EsConstant;
import com.yufubao.framework.util.MyCollUtil;
import com.yufubao.model.dto.applet.search.SearchParam;
import com.yufubao.model.pojo.applet.elasticsearch.SupplierEsModel;
import com.yufubao.model.vo.applet.search.SearchResult;
import com.yufubao.service.service.applet.elasticsearch.AppletSearchService;
import org.apache.lucene.search.TotalHits;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.NestedQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.nested.NestedAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.nested.ParsedNested;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedLongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import static com.yufubao.framework.constant.EsConstant.PAGE_SIZE;

/**
 * @author 张一恒
 * @version 1.0
 * @description:
 * @date 2024/9/3 17:25
 */
@Service("appletSearch")
public class AppletSearchServiceImpl implements AppletSearchService {
    @Autowired
    private RestHighLevelClient restHighLevelClient;

    /**
     * @param searchParam
     * @return com.yufubao.model.vo.search.SearchResult
     * @description 小程序es检索商户
     * @author zhangyiheng
     * @date 2024/9/3 17:31
     */
    @Override
    public SearchResult listPage(SearchParam searchParam) {
        //创建搜索请求 1.组装模糊搜索条件、过滤条件（精确过滤）、(2.排序、3.分页、4.高亮)、5.聚合搜索、收集组装后的请求对象、收集字段元素并返回
        //关于价格检索需要查询数据库

        //创建搜索请求
        SearchRequest searchRequest = new SearchRequest(EsConstant.SUPPLIER_INDEX);


        //组装模糊搜索条件 组装模糊搜索条件、（精确过滤）、(2.排序、3.分页、4.高亮)、聚合搜索
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        //构建请求DSL
        builderDSL(searchParam, searchSourceBuilder);

        //收集字段元素并返回
        SearchResult searchResult = new SearchResult();
        try {
            //收集组装后的请求对象
            searchRequest.source(searchSourceBuilder);

            SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptionsBuilder.COMMON_OPTIONS);
            SearchHits hits = search.getHits();
            searchResult = new SearchResult();

            //保存查询到的所有商品信息
            List<SupplierEsModel> supplierEsModels = new ArrayList<>();
            SearchHit[] data = hits.getHits();
            if (!Objects.isNull(data)) {
                for (SearchHit hit : data) {
                    String dataJson = hit.getSourceAsString();
                    SupplierEsModel supplierEsModel = JSON.parseObject(dataJson, SupplierEsModel.class);
                    //设置高亮
                    if (StrUtil.isNotBlank(searchParam.getKeyword())) {
                        HighlightField storeName = hit.getHighlightFields().get("storeName");
                        HighlightField address = hit.getHighlightFields().get("address");
                        if (storeName.getFragments() != null) {
                            for (Text text : storeName.getFragments()) {
                                supplierEsModel.setStoreName(text.toString());
                            }
                        }
                        if (address.getFragments() != null) {
                            for (Text text : address.getFragments()) {
                                supplierEsModel.setAddress(text.toString());
                            }
                        }

                    }
                    supplierEsModels.add(supplierEsModel);
                }
                searchResult.setSupplierEsModels(supplierEsModels);
            }

            //保存分页数据
            TotalHits totalHits = hits.getTotalHits();
            searchResult.setTotal(totalHits.value);

            Integer pageNum = searchParam.getPageNumber();
            searchResult.setPageNum(pageNum);

            searchResult.setTotalPages(((int) totalHits.value % PAGE_SIZE) == 0 ? (int) totalHits.value / PAGE_SIZE : ((int) totalHits.value / PAGE_SIZE + 1));

            List<Integer> list = new ArrayList<>();
            for (int i = 1; i <= searchResult.getTotalPages(); i++) {
                list.add(i);
            }
            searchResult.setTotalPagesList(list);



            //保存所有涉及到的分类
            ParsedLongTerms categoryAgg = search.getAggregations().get("catalog_agg");
            List<? extends Terms.Bucket> categoryAggBuckets = categoryAgg.getBuckets();
            List<SearchResult.CategoryVo> categorys = new ArrayList<>();
            if (MyCollUtil.isNotEmpty(categoryAggBuckets)) {
                for (Terms.Bucket categoryAggBucket : categoryAggBuckets) {
                    SearchResult.CategoryVo catalogVo = new SearchResult.CategoryVo();
                    catalogVo.setCategoryId((Long) categoryAggBucket.getKey());

                    ParsedStringTerms categoryNameAgg = categoryAggBucket.getAggregations().get("category_name_agg");
                    if (!Objects.isNull(categoryNameAgg)) {
                        List<? extends Terms.Bucket> categoryNameAggBuckets = categoryNameAgg.getBuckets();
                        if (MyCollUtil.isNotEmpty(categoryNameAggBuckets)) {
                            for (Terms.Bucket categoryNameAggBucket : categoryNameAggBuckets) {
                                catalogVo.setCategoryName(categoryNameAggBucket.getKey().toString());
                            }
                        }
                    }
                    categorys.add(catalogVo);
                }
            }
            searchResult.setCategorys(categorys);

            //保存所有涉及到的商品属性
            ParsedNested attrAgg = search.getAggregations().get("attr_agg");
            ParsedLongTerms attrIdAgg = attrAgg.getAggregations().get("attr_id_agg");
            List<SearchResult.AttrVo> attrs = new ArrayList<>();
            if (!Objects.isNull(attrIdAgg)) {
                List<? extends Terms.Bucket> attrIdAggBuckets = attrIdAgg.getBuckets();
                if (MyCollUtil.isNotEmpty(attrIdAggBuckets)) {
                    for (Terms.Bucket attrIdAggBucket : attrIdAggBuckets) {
                        SearchResult.AttrVo attr = new SearchResult.AttrVo();
                        attr.setAttrId((Long) attrIdAggBucket.getKey());

                        ParsedStringTerms attrNameAgg = attrIdAggBucket.getAggregations().get("attr_name_agg");
                        List<? extends Terms.Bucket> attrNameAggBuckets = attrNameAgg.getBuckets();
                        if (MyCollUtil.isNotEmpty(attrNameAggBuckets)) {
                            for (Terms.Bucket attrNameAggBucket : attrNameAggBuckets) {
                                attr.setAttrName(attrNameAggBucket.getKey().toString());
                            }
                        }

                        ParsedStringTerms attrValueAgg = attrIdAggBucket.getAggregations().get("attr_values_agg");
                        List<? extends Terms.Bucket> attrValueAggBuckets = attrValueAgg.getBuckets();
                        List<String> attrValue = new ArrayList<>();
                        if (MyCollUtil.isNotEmpty(attrValueAggBuckets)) {
                            for (Terms.Bucket attrValueAggBucket : attrValueAggBuckets) {
                                attrValue.add(attrValueAggBucket.getKey().toString());
                            }
                        }
                        attr.setAttrValue(attrValue);

                        attrs.add(attr);
                    }
                }
            }
            searchResult.setAttrs(attrs);
        } catch (Exception ignored) {
        }

        return searchResult;
    }


    private void builderDSL(SearchParam searchParam, SearchSourceBuilder searchSourceBuilder) {
        //region 1.组装模糊搜索条件、（精确过滤）
        //整体查询 用于匹配与其他查询的布尔组合匹配
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        //组装模糊搜索/全文搜索
        if (StrUtil.isNotBlank(searchParam.getKeyword())) {
            boolQueryBuilder.must(QueryBuilders.multiMatchQuery(searchParam.getKeyword(), "storeName", "address"));
        }


        //分类id
        if (!Objects.isNull(searchParam.getCategory3Id())) {
            boolQueryBuilder.filter(QueryBuilders.termQuery("categoryId", searchParam.getCategory3Id()));
        }

//        //TODO 价格区间  0_500,_500,500_
//        if (StrUtil.isNotBlank(searchParam.getSkuPrice())) {
//            String skuPrice = searchParam.getSkuPrice();
//            String[] price = skuPrice.split("_");
//            if (skuPrice.startsWith("_")) {
//                boolQueryBuilder.filter(QueryBuilders.rangeQuery("skuPrice").lte(price[1]));
//            } else if (skuPrice.endsWith("_")) {
//                boolQueryBuilder.filter(QueryBuilders.rangeQuery("skuPrice").gte(price[0]));
//            } else {
//                boolQueryBuilder.filter(QueryBuilders.rangeQuery("skuPrice").gte(price[0]));
//                boolQueryBuilder.filter(QueryBuilders.rangeQuery("skuPrice").lte(price[1]));
//            }
//        }


        //attrs  1_5寸:8寸
        if (MyCollUtil.isNotEmpty(searchParam.getAttrs())) {
            for (String attr : searchParam.getAttrs()) {
                BoolQueryBuilder nestededBoolQueryBuilder = QueryBuilders.boolQuery();
                //组装attrId
                String attrId = attr.split("_")[0];
                nestededBoolQueryBuilder.filter(QueryBuilders.termQuery("spuAttrs.attrId", attrId));
                //组装attrValue
                String attrValues = attr.split("_")[1];
                String[] values = attrValues.split(":");
                nestededBoolQueryBuilder.filter(QueryBuilders.termsQuery("spuAttrs.attrValue.keyword", values));


                NestedQueryBuilder nesteded = QueryBuilders.nestedQuery("spuAttrs", nestededBoolQueryBuilder, ScoreMode.None);
                boolQueryBuilder.filter(nesteded);
            }
        }


        searchSourceBuilder.query(boolQueryBuilder);
        //endregion


        //region (2.排序、3.分页、4.高亮)
        //排序 sort=price/saleCount/hotScore_desc/asc
        if (StrUtil.isNotBlank(searchParam.getSort())) {
            String sort = searchParam.getSort();
            String sortName = sort.split("_")[0];
            String sortOrder = sort.split("_")[1];
            SortOrder order = sortOrder.equals("asc") ? SortOrder.ASC : SortOrder.DESC;
            searchSourceBuilder.sort(sortName, order);
        }

        //分页
        searchSourceBuilder.from((searchParam.getPageNumber() - 1) * PAGE_SIZE);
        searchSourceBuilder.size(PAGE_SIZE);

        //高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder();

        highlightBuilder.field("storeName").field("address").field("spuAttrs.attrValue");
        highlightBuilder.preTags("<b style='color:red'>");
        highlightBuilder.postTags("</b>");
        searchSourceBuilder.highlighter(highlightBuilder);
        //endregion


        //属性聚合
        NestedAggregationBuilder nested = AggregationBuilders.nested("attr_agg", "spuAttrs");
        nested.subAggregation(AggregationBuilders.terms("attr_id_agg").field("spuAttrs.attrId").size(100)
                //属性名
                .subAggregation(AggregationBuilders.terms("attr_name_agg").field("spuAttrs.attrName").size(100))
                //属性值
                .subAggregation(AggregationBuilders.terms("attr_values_agg").field("spuAttrs.attrValue.keyword").size(100)));
        searchSourceBuilder.aggregation(nested);
        //endregion

        System.out.println(searchSourceBuilder.toString());
    }
}
